package com.lhz.framework.security.interceptor;

import cn.hutool.core.lang.Assert;
import cn.hutool.json.JSONUtil;
import com.lhz.common.constant.ResponseState;
import com.lhz.common.constant.TokenConstant;
import com.lhz.framework.security.HolderInfoManager;
import com.lhz.framework.security.HolderUserInfo;
import com.lhz.framework.security.annotation.CheckPermission;
import com.lhz.framework.security.annotation.IgnoreToken;
import com.lhz.framework.security.manager.SecurityManager;
import com.lhz.framework.security.token.DataTokenInfo;
import com.lhz.framework.security.token.UserTokenInfo;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;

/**
 * Token身份验证
 *
 * @author lihuazhi
 */
@Component
@Slf4j
public class AuthenticationHandlerInterceptor implements HandlerInterceptor {

    @Resource
    private SecurityManager<Object> securityManager;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String path = request.getServletPath();
        //GET、PUT、DELETE、POST
        String httpMethod = request.getMethod();

        log.info("认证拦截器请求的method:{} url:{} param:{}", httpMethod, path, "x");

        Method method = ((HandlerMethod) handler).getMethod();

        // 忽略token检测
        if (method.isAnnotationPresent(IgnoreToken.class)) {
            return true;
        }

        // 获取token
        //定义的header名称
        String token = request.getHeader(TokenConstant.TOKEN_NAME);

        Assert.notNull(token, ResponseState.TOKEN_ERROR.name());

        Assert.isTrue(securityManager.checkToken(token), ResponseState.TOKEN_ERROR.name());

        //获取用户信息
        Map<String, Object> userInfo = (Map<String, Object>) securityManager.getUserInfo(token);

        //加入用户全局信息
        HolderInfoManager.addUserId(userInfo.get("userId").toString());
        HolderInfoManager.addUserName(userInfo.get("userName").toString());
        HolderInfoManager.addToken(token);
        HolderInfoManager.addRequest(request);
        HolderInfoManager.addResponse(response);
        String jsonString = JSONUtil.toJsonStr(userInfo.get("userInfo"));
        HolderUserInfo holderUserInfo = JSONUtil.toBean(jsonString, HolderUserInfo.class);
        if (holderUserInfo != null) {
            HolderInfoManager.addUserInfo(holderUserInfo);
            UserTokenInfo user = holderUserInfo.getUser();
            HolderInfoManager.addUserId(user.getId());
            HolderInfoManager.setDeptId(user.getDeptId());
            DataTokenInfo dataTokenInfo = holderUserInfo.getDataTokenInfo();
            HolderInfoManager.setDataScope(dataTokenInfo.getDataScope());
            HolderInfoManager.setDeptIds(dataTokenInfo.getDeptIds());
        }

        //进行功能权限
        List<String> permissionList = HolderInfoManager.getUserInfo().getPermissionList();
        //非系统管理员 进行权限验证
        if (!permissionList.contains("*:*:*") && method.isAnnotationPresent(CheckPermission.class)) {
            CheckPermission annotation = method.getAnnotation(CheckPermission.class);
            String[] codes = annotation.code();
            int errorSize = 0;//记录不匹配次数
            for (String code : codes) {
                if (!permissionList.contains(code)) {
                    errorSize++;
                }
            }
            //如果不匹配次数等于要求权限长度
            Assert.isFalse(errorSize == codes.length, ResponseState.NOT_AUTH.name());

        }
        //token验证通过，重新更新时长
        securityManager.refreshExpiry(token);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

    }
}
